{
  "cells": [
    {
      "cell_type": "code",
      "execution_count": 1,
      "metadata": {
        "ExecuteTime": {
          "end_time": "2020-05-25T13:51:35.454012Z",
          "start_time": "2020-05-25T13:51:34.972447Z"
        },
        "pycharm": {}
      },
      "outputs": [],
      "source": "import pandas as pd\nfrom tqdm import tqdm\nfrom collections import defaultdict\nimport math\n\ndef get_sim_item(df_, user_col, item_col, use_iif\u003dFalse): \n    df \u003d df_.copy()\n    user_item_ \u003d df.groupby(user_col)[item_col].agg(list).reset_index()\n    user_item_dict \u003d dict(zip(user_item_[user_col], user_item_[item_col]))\n    \n    user_time_ \u003d df.groupby(user_col)[\u0027time\u0027].agg(list).reset_index() # 引入时间因素\n    user_time_dict \u003d dict(zip(user_time_[user_col], user_time_[\u0027time\u0027]))\n    \n    sim_item \u003d {}  \n    item_cnt \u003d defaultdict(int)  # 商品被点击次数\n    for user, items in tqdm(user_item_dict.items()):  \n        for loc1, item in enumerate(items):  \n            item_cnt[item] +\u003d 1  \n            sim_item.setdefault(item, {})  \n            for loc2, relate_item in enumerate(items):  \n                if item \u003d\u003d relate_item:  \n                    continue  \n                t1 \u003d user_time_dict[user][loc1] # 点击时间提取\n                t2 \u003d user_time_dict[user][loc2]\n                sim_item[item].setdefault(relate_item, 0)  \n                if not use_iif:  \n                    if loc1-loc2\u003e0:\n                        sim_item[item][relate_item] +\u003d 1 * 0.7 * (0.8**(loc1-loc2-1)) * (1 - (t1 - t2) * 10000) / math.log(1 + len(items)) # 逆向\n                    else:\n                        sim_item[item][relate_item] +\u003d 1 * 1.0 * (0.8**(loc2-loc1-1)) * (1 - (t2 - t1) * 10000) / math.log(1 + len(items)) # 正向\n                else:  \n                    sim_item[item][relate_item] +\u003d 1 / math.log(1 + len(items))  \n\n    sim_item_corr \u003d sim_item.copy() # 引入AB的各种被点击次数  \n    for i, related_items in tqdm(sim_item.items()):  \n        for j, cij in related_items.items():  \n            sim_item_corr[i][j] \u003d cij / ((item_cnt[i] * item_cnt[j]) ** 0.2)  \n  \n    return sim_item_corr, user_item_dict  "
    },
    {
      "cell_type": "code",
      "execution_count": 2,
      "metadata": {
        "ExecuteTime": {
          "end_time": "2020-05-25T13:51:35.466611Z",
          "start_time": "2020-05-25T13:51:35.457823Z"
        },
        "pycharm": {}
      },
      "outputs": [],
      "source": [
        "def recommend(sim_item_corr, user_item_dict, user_id, top_k, item_num):  \n",
        "    \u0027\u0027\u0027\n",
        "    input:item_sim_list, user_item, uid, 500, 50\n",
        "    # 用户历史序列中的所有商品均有关联商品,整合这些关联商品,进行相似性排序\n",
        "    \u0027\u0027\u0027\n",
        "    rank \u003d {}  \n",
        "    interacted_items \u003d user_item_dict[user_id] \n",
        "    interacted_items \u003d interacted_items[::-1]\n",
        "    for loc, i in enumerate(interacted_items):  \n",
        "        for j, wij in sorted(sim_item_corr[i].items(), reverse\u003dTrue)[0:top_k]:  \n",
        "            if j not in interacted_items:  \n",
        "                rank.setdefault(j, 0)  \n",
        "                rank[j] +\u003d wij * (0.7**loc) \n",
        "\n",
        "    \n",
        "    return sorted(rank.items(), key\u003dlambda d: d[1], reverse\u003dTrue)[:item_num]  "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "metadata": {
        "ExecuteTime": {
          "end_time": "2020-05-25T13:51:35.482145Z",
          "start_time": "2020-05-25T13:51:35.468933Z"
        },
        "pycharm": {}
      },
      "outputs": [],
      "source": [
        "# fill user to 50 items  \n",
        "def get_predict(df, pred_col, top_fill):  \n",
        "    top_fill \u003d [int(t) for t in top_fill.split(\u0027,\u0027)]  \n",
        "    scores \u003d [-1 * i for i in range(1, len(top_fill) + 1)]  \n",
        "    ids \u003d list(df[\u0027user_id\u0027].unique())  \n",
        "    fill_df \u003d pd.DataFrame(ids * len(top_fill), columns\u003d[\u0027user_id\u0027])  \n",
        "    fill_df.sort_values(\u0027user_id\u0027, inplace\u003dTrue)  \n",
        "    fill_df[\u0027item_id\u0027] \u003d top_fill * len(ids)  \n",
        "    fill_df[pred_col] \u003d scores * len(ids)  \n",
        "    df \u003d df.append(fill_df)  \n",
        "    df.sort_values(pred_col, ascending\u003dFalse, inplace\u003dTrue)  \n",
        "    df \u003d df.drop_duplicates(subset\u003d[\u0027user_id\u0027, \u0027item_id\u0027], keep\u003d\u0027first\u0027)  \n",
        "    df[\u0027rank\u0027] \u003d df.groupby(\u0027user_id\u0027)[pred_col].rank(method\u003d\u0027first\u0027, ascending\u003dFalse)  \n",
        "    df \u003d df[df[\u0027rank\u0027] \u003c\u003d 50]  \n",
        "    df \u003d df.groupby(\u0027user_id\u0027)[\u0027item_id\u0027].apply(lambda x: \u0027,\u0027.join([str(i) for i in x])).str.split(\u0027,\u0027, expand\u003dTrue).reset_index()  \n",
        "    return df  "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 19,
      "metadata": {
        "ExecuteTime": {
          "end_time": "2020-05-25T14:09:01.020577Z",
          "start_time": "2020-05-25T14:08:39.313686Z"
        },
        "pycharm": {}
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "phase: 0\n"
          ]
        },
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "100%|██████████| 18505/18505 [00:06\u003c00:00, 2851.99it/s]\n",
            "100%|██████████| 40776/40776 [00:02\u003c00:00, 18387.35it/s]\n",
            "100%|██████████| 1663/1663 [00:06\u003c00:00, 238.82it/s]\n"
          ]
        }
      ],
      "source": [
        "now_phase \u003d 0\n",
        "train_path \u003d \u0027/Users/ed/Data/2020-kdd-debiasing/underexpose_train\u0027  \n",
        "test_path \u003d \u0027/Users/ed/Data/2020-kdd-debiasing/underexpose_test\u0027  \n",
        "recom_item \u003d []  \n",
        "\n",
        "whole_click \u003d pd.DataFrame()  \n",
        "for c in range(now_phase + 1):  \n",
        "    print(\u0027phase:\u0027, c)  \n",
        "    click_train \u003d pd.read_csv(train_path + \u0027/underexpose_train_click-{}.csv\u0027.format(c), header\u003dNone,  names\u003d[\u0027user_id\u0027, \u0027item_id\u0027, \u0027time\u0027])  \n",
        "    click_test \u003d pd.read_csv(test_path + \u0027/underexpose_test_click-{}.csv\u0027.format(c,c), header\u003dNone,  names\u003d[\u0027user_id\u0027, \u0027item_id\u0027, \u0027time\u0027])  \n",
        "\n",
        "    all_click \u003d click_train.append(click_test)  \n",
        "    whole_click \u003d whole_click.append(all_click)  \n",
        "    whole_click \u003d whole_click.drop_duplicates(subset\u003d[\u0027user_id\u0027,\u0027item_id\u0027,\u0027time\u0027],keep\u003d\u0027last\u0027)\n",
        "    whole_click \u003d whole_click.sort_values(\u0027time\u0027)\n",
        "\n",
        "    item_sim_list, user_item \u003d get_sim_item(whole_click, \u0027user_id\u0027, \u0027item_id\u0027, use_iif\u003dFalse)  \n",
        "\n",
        "    for i in tqdm(click_test[\u0027user_id\u0027].unique()):  \n",
        "        rank_item \u003d recommend(item_sim_list, user_item, i, 500, 500)  \n",
        "        for j in rank_item:  \n",
        "            recom_item.append([i, j[0], j[1]])  \n",
        "            \n",
        "# find most popular items  \n",
        "top50_click \u003d whole_click[\u0027item_id\u0027].value_counts().index[:50].values  \n",
        "top50_click \u003d \u0027,\u0027.join([str(i) for i in top50_click])  \n",
        "\n",
        "recom_df \u003d pd.DataFrame(recom_item, columns\u003d[\u0027user_id\u0027, \u0027item_id\u0027, \u0027sim\u0027])  \n",
        "result \u003d get_predict(recom_df, \u0027sim\u0027, top50_click)  \n",
        "result.to_csv(\u0027baseline.csv\u0027, index\u003dFalse, header\u003dNone)"
      ]
    }
  ],
  "metadata": {
    "celltoolbar": "Raw Cell Format",
    "kernelspec": {
      "display_name": "Python [conda env:pytorch]",
      "language": "python",
      "name": "conda-env-pytorch-py"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.5.5"
    },
    "toc": {
      "base_numbering": 1,
      "nav_menu": {},
      "number_sections": true,
      "sideBar": true,
      "skip_h1_title": false,
      "title_cell": "Table of Contents",
      "title_sidebar": "Contents",
      "toc_cell": false,
      "toc_position": {},
      "toc_section_display": true,
      "toc_window_display": false
    }
  },
  "nbformat": 4,
  "nbformat_minor": 2
}